package cn.cloud9.activiti7;

import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Test;

import java.io.*;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipInputStream;

/**
 * @author OnCloud9
 * @description
 * @project activiti7
 * @date 2022年08月20日 上午 11:26
 */
public class ProcessApi {

    private ProcessEngine processEngine;
    private RepositoryService repositoryService;
    private RuntimeService runtimeService;
    private TaskService taskService;
    private HistoryService historyService;
    private ManagementService managementService;

    /**
     * 初始化预备资源
     */
    @Before
    public void loadingResource() {
        processEngine = ProcessEngines.getDefaultProcessEngine();
        repositoryService = processEngine.getRepositoryService();
        runtimeService = processEngine.getRuntimeService();
        taskService = processEngine.getTaskService();
        historyService = processEngine.getHistoryService();
        managementService = processEngine.getManagementService();
    }

    /**
     * 1、部署[流程定义]
     *
     * -- 插入流程部署记录和流程定义记录
     *  Preparing: insert into ACT_RE_PROCDEF(ID_, REV_, CATEGORY_, NAME_, KEY_, VERSION_, DEPLOYMENT_ID_, RESOURCE_NAME_, DGRM_RESOURCE_NAME_, DESCRIPTION_, HAS_START_FORM_KEY_, HAS_GRAPHICAL_NOTATION_ , SUSPENSION_STATE_, TENANT_ID_, ENGINE_VERSION_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
     * Parameters: MyEvection:1:4(String), http://www.activiti.org/processdef(String), 我的出差申请流程(String), MyEvection(String), 1(Integer), 1(String), ./bpmn/evection.bpmn20.xml(String), ./bpmn/evection.png(String), 我的出差申请流程，这里是文档注释信息(String), false(Boolean), true(Boolean), 1(Integer), (String), null
     *    Updates: 1
     *
     *  Preparing: insert into ACT_RE_DEPLOYMENT(ID_, NAME_, CATEGORY_, KEY_, TENANT_ID_, DEPLOY_TIME_, ENGINE_VERSION_) values(?, ?, ?, ?, ?, ?, ?)
     * Parameters: 1(String), 出差申请流程(String), null, null, (String), 2022-08-20 11:42:12.656(Timestamp), null
     *    Updates: 1
     *
     *  Preparing: INSERT INTO ACT_GE_BYTEARRAY(ID_, REV_, NAME_, BYTES_, DEPLOYMENT_ID_, GENERATED_) VALUES (?, 1, ?, ?, ?, ?) , (?, 1, ?, ?, ?, ?)
     * Parameters: 2(String), ./bpmn/evection.png(String), java.io.ByteArrayInputStream@33aeca0b(ByteArrayInputStream), 1(String), false(Boolean), 3(String), ./bpmn/evection.bpmn20.xml(String), java.io.ByteArrayInputStream@43aaf813(ByteArrayInputStream), 1(String), false(Boolean)
     *    Updates: 2
     *
     * -- 插入结果
     * id = 1
     * deploymentTime = Sat Aug 20 11:42:12 CST 2022
     * name = 出差申请流程
     * key = null
     * tenantId =
     *
     */
    @Test
    public void deploymentProcess() {
        final DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();

        final Deployment deployment =  deploymentBuilder
                .name("出差申请流程")
                .addClasspathResource("./bpmn/evection.bpmn20.xml")
                .addClasspathResource("./bpmn/evection.png")
                .deploy();

        final String id = deployment.getId();
        final Date deploymentTime = deployment.getDeploymentTime();
        final String name = deployment.getName();
        final String key = deployment.getKey();
        final String tenantId = deployment.getTenantId();

        System.out.println("id = " + id);
        System.out.println("deploymentTime = " + deploymentTime);
        System.out.println("name = " + name);
        System.out.println("key = " + key);
        System.out.println("tenantId = " + tenantId);
    }

    /**
     * 下载部署资源
     * @throws IOException
     */
    @Test
    public void downloadDeploymentResource() throws IOException {
        final ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
        final ProcessDefinition processDefinition = query
                .processDefinitionKey("MyEvection")
                .singleResult();

        final String deploymentId = processDefinition.getDeploymentId();
        final String bpmnResourcePath = processDefinition.getDiagramResourceName();
        final String pngResourcePath = processDefinition.getResourceName();

        final InputStream bpmnInputStream = repositoryService.getResourceAsStream(deploymentId, bpmnResourcePath);
        final InputStream pngInputStream = repositoryService.getResourceAsStream(deploymentId, pngResourcePath);

        String outputPath = "E:\\output\\";

        final File bpmnFile = new File(outputPath + bpmnResourcePath.substring(bpmnResourcePath.lastIndexOf("/") + 1));
        final File pngFile = new File(outputPath + pngResourcePath.substring(pngResourcePath.lastIndexOf("/") + 1));

        FileOutputStream bpmnFileOutputStream = null;
        FileOutputStream pngFileOutputStream = null;
        try {
            bpmnFileOutputStream = new FileOutputStream(bpmnFile);
            pngFileOutputStream = new FileOutputStream(pngFile);

            IOUtils.copy(bpmnInputStream, bpmnFileOutputStream);
            IOUtils.copy(pngInputStream, pngFileOutputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            pngFileOutputStream.close();
            bpmnFileOutputStream.close();
            pngInputStream.close();
            bpmnInputStream.close();
        }
    }

    /**
     * 使用zip包方式部署流程
     *
     * id = 1
     * deploymentTime = Sat Aug 20 13:47:45 CST 2022
     * name = null
     * key = null
     * tenantId =
     */
    @Test
    public void deploymentProcessUsingZip() {
        // 获取zip流
        final InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("./bpmn/evection.zip");
        assert inputStream != null;
        final ZipInputStream zipInputStream = new ZipInputStream(inputStream);

        final DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
        final Deployment deployment = deploymentBuilder
                .addZipInputStream(zipInputStream)
                .deploy();

        final String id = deployment.getId();
        final Date deploymentTime = deployment.getDeploymentTime();
        final String name = deployment.getName();
        final String key = deployment.getKey();
        final String tenantId = deployment.getTenantId();

        System.out.println("id = " + id);
        System.out.println("deploymentTime = " + deploymentTime);
        System.out.println("name = " + name);
        System.out.println("key = " + key);
        System.out.println("tenantId = " + tenantId);

        try {
            inputStream.close();
            zipInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 启动流程
     *  Preparing: insert into ACT_HI_TASKINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TASK_DEF_KEY_, FORM_KEY_, PRIORITY_, DUE_DATE_, CATEGORY_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
     * Parameters: 2505(String), MyEvection:1:4(String), 2501(String), 2502(String), 创建出差申请(String), null, null, null, 张三(String), 2022-08-20 11:49:03.991(Timestamp), null, null, null, null, sid-7d4155ad-908b-4a3f-b474-29db1e5d3f79(String), null, 50(Integer), null, null, (String)
     *    Updates: 1
     * rting: HistoricProcessInstanceEntity[superProcessInstanceId=null]
     *  Preparing: insert into ACT_HI_PROCINST ( ID_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, START_TIME_, END_TIME_, DURATION_, START_USER_ID_, START_ACT_ID_, END_ACT_ID_, SUPER_PROCESS_INSTANCE_ID_, DELETE_REASON_, TENANT_ID_, NAME_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
     * Parameters: 2501(String), 2501(String), null, MyEvection:1:4(String), 2022-08-20 11:49:03.903(Timestamp), null, null, null, sid-2518b893-c58d-4b21-b74d-dcf4861a4f3f(String), null, null, null, (String), null
     *    Updates: 1
     *  Preparing: insert into ACT_HI_ACTINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_, ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TENANT_ID_ ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
     * Parameters: 2503(String), MyEvection:1:4(String), 2501(String), 2502(String), sid-2518b893-c58d-4b21-b74d-dcf4861a4f3f(String), null, null, StartEvent(String), startEvent(String), null, 2022-08-20 11:49:03.962(Timestamp), 2022-08-20 11:49:03.965(Timestamp), 3(Long), null, (String), 2504(String), MyEvection:1:4(String), 2501(String), 2502(String), sid-7d4155ad-908b-4a3f-b474-29db1e5d3f79(String), 2505(String), null, 创建出差申请(String), userTask(String), 张三(String), 2022-08-20 11:49:03.97(Timestamp), null, null, null, (String)
     *    Updates: 2
     * rting: org.activiti.engine.impl.persistence.entity.HistoricIdentityLinkEntityImpl@774698ab
     *  Preparing: insert into ACT_HI_IDENTITYLINK (ID_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_) values (?, ?, ?, ?, ?, ?)
     * Parameters: 2506(String), participant(String), 张三(String), null, null, 2501(String)
     *    Updates: 1
     *  Preparing: insert into ACT_RU_EXECUTION (ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_,IS_EVENT_SCOPE_, IS_MI_ROOT_, PARENT_ID_, SUPER_EXEC_, ROOT_PROC_INST_ID_, SUSPENSION_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_, TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) , (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
     * Parameters: 2501(String), 2501(String), null, MyEvection:1:4(String), null, true(Boolean), false(Boolean), true(Boolean), false(Boolean), false(Boolean), null, null, 2501(String), 1(Integer), (String), null, 2022-08-20 11:49:03.903(Timestamp), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 2502(String), 2501(String), null, MyEvection:1:4(String), sid-7d4155ad-908b-4a3f-b474-29db1e5d3f79(String), true(Boolean), false(Boolean), false(Boolean), false(Boolean), false(Boolean), 2501(String), null, 2501(String), 1(Integer), (String), null, 2022-08-20 11:49:03.96(Timestamp), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer)
     *    Updates: 2
     * rting: Task[id=2505, name=创建出差申请]
     *  Preparing: insert into ACT_RU_TASK (ID_, REV_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, PRIORITY_, CREATE_TIME_, OWNER_, ASSIGNEE_, DELEGATION_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, TASK_DEF_KEY_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_, FORM_KEY_, CLAIM_TIME_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
     * Parameters: 2505(String), 创建出差申请(String), null, null, 50(Integer), 2022-08-20 11:49:03.97(Timestamp), null, 张三(String), null, 2502(String), 2501(String), MyEvection:1:4(String), sid-7d4155ad-908b-4a3f-b474-29db1e5d3f79(String), null, null, 1(Integer), (String), null, null
     *    Updates: 1
     * rting: IdentityLinkEntity[id=2506, type=participant, userId=张三, processInstanceId=2501]
     *  Preparing: insert into ACT_RU_IDENTITYLINK (ID_, REV_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_, PROC_DEF_ID_) values (?, 1, ?, ?, ?, ?, ?, ?)
     * Parameters: 2506(String), participant(String), 张三(String), null, null, 2501(String), null
     *
     */
    @Test
    public void startProcess() {
        final ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("MyEvection");

        final String deploymentId = processInstance.getDeploymentId();
        final String processDefinitionId = processInstance.getProcessDefinitionId();
        final String activityId = processInstance.getActivityId();

        System.out.println("流程部署ID deploymentId = " + deploymentId);
        System.out.println("流程定义ID processDefinitionId = " + processDefinitionId);
        System.out.println("流程活动ID activityId = " + activityId);
    }


    /**
     *  Preparing: select distinct RES.* from ACT_RU_TASK RES inner join ACT_RE_PROCDEF D on RES.PROC_DEF_ID_ = D.ID_ WHERE RES.ASSIGNEE_ = ? and D.KEY_ = ? order by RES.ID_ asc LIMIT ? OFFSET ?
     * Parameters: 张三(String), MyEvection(String), 2147483647(Integer), 0(Integer)
     *      Total: 1
     */
    @Test
    public void taskQuery() {
        final TaskQuery taskQuery = taskService.createTaskQuery();

        final Task task = taskQuery
                .processDefinitionKey("MyEvection")
                .taskAssignee("张三")
                .singleResult();

        final String id = task.getId();
        final String name = task.getName();
        final String processDefinitionId = task.getProcessDefinitionId();
        final String assignee = task.getAssignee();

        System.out.println("id = " + id);
        System.out.println("name = " + name);
        System.out.println("processDefinitionId = " + processDefinitionId);
        System.out.println("assignee = " + assignee);
    }

    /**
     * 完成[我的出差申请]流程任务
     *
     *  Preparing: insert into ACT_HI_TASKINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TASK_DEF_KEY_, FORM_KEY_, PRIORITY_, DUE_DATE_, CATEGORY_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
     * Parameters: 5002(String), MyEvection:1:4(String), 2501(String), 2502(String), 经理审批(String), null, null, null, Jack张(String), 2022-08-20 12:38:40.675(Timestamp), null, null, null, null, sid-84549a66-648c-4255-990c-313ad7e9af6b(String), null, 50(Integer), null, null, (String)
     *    Updates: 1
     * rting: HistoricActivityInstanceEntity[id=5001, activityId=sid-84549a66-648c-4255-990c-313ad7e9af6b, activityName=经理审批]
     *  Preparing: insert into ACT_HI_ACTINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_, ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
     * Parameters: 5001(String), MyEvection:1:4(String), 2501(String), 2502(String), sid-84549a66-648c-4255-990c-313ad7e9af6b(String), 5002(String), null, 经理审批(String), userTask(String), Jack张(String), 2022-08-20 12:38:40.664(Timestamp), null, null, null, (String)
     *    Updates: 1
     * rting: org.activiti.engine.impl.persistence.entity.HistoricIdentityLinkEntityImpl@79145d5a
     *  Preparing: insert into ACT_HI_IDENTITYLINK (ID_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_) values (?, ?, ?, ?, ?, ?)
     * Parameters: 5003(String), participant(String), Jack张(String), null, null, 2501(String)
     *    Updates: 1
     * rting: Task[id=5002, name=经理审批]
     *  Preparing: insert into ACT_RU_TASK (ID_, REV_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, PRIORITY_, CREATE_TIME_, OWNER_, ASSIGNEE_, DELEGATION_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, TASK_DEF_KEY_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_, FORM_KEY_, CLAIM_TIME_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
     * Parameters: 5002(String), 经理审批(String), null, null, 50(Integer), 2022-08-20 12:38:40.664(Timestamp), null, Jack张(String), null, 2502(String), 2501(String), MyEvection:1:4(String), sid-84549a66-648c-4255-990c-313ad7e9af6b(String), null, null, 1(Integer), (String), null, null
     *    Updates: 1
     * rting: IdentityLinkEntity[id=5003, type=participant, userId=Jack张, processInstanceId=2501]
     *  Preparing: insert into ACT_RU_IDENTITYLINK (ID_, REV_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_, PROC_DEF_ID_) values (?, 1, ?, ?, ?, ?, ?, ?)
     * Parameters: 5003(String), participant(String), Jack张(String), null, null, 2501(String), null
     *    Updates: 1
     * ting: Execution[ id '2502' ] - activity 'sid-84549a66-648c-4255-990c-313ad7e9af6b - parent '2501'
     *  Preparing: update ACT_RU_EXECUTION set REV_ = ?, BUSINESS_KEY_ = ?, PROC_DEF_ID_ = ?, ACT_ID_ = ?, IS_ACTIVE_ = ?, IS_CONCURRENT_ = ?, IS_SCOPE_ = ?, IS_EVENT_SCOPE_ = ?, IS_MI_ROOT_ = ?, PARENT_ID_ = ?, SUPER_EXEC_ = ?, ROOT_PROC_INST_ID_ = ?, SUSPENSION_STATE_ = ?, NAME_ = ?, IS_COUNT_ENABLED_ = ?, EVT_SUBSCR_COUNT_ = ?, TASK_COUNT_ = ?, JOB_COUNT_ = ?, TIMER_JOB_COUNT_ = ?, SUSP_JOB_COUNT_ = ?, DEADLETTER_JOB_COUNT_ = ?, VAR_COUNT_ = ?, ID_LINK_COUNT_ = ? where ID_ = ? and REV_ = ?
     * Parameters: 2(Integer), null, MyEvection:1:4(String), sid-84549a66-648c-4255-990c-313ad7e9af6b(String), true(Boolean), false(Boolean), false(Boolean), false(Boolean), false(Boolean), 2501(String), null, 2501(String), 1(Integer), null, false(Boolean), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 0(Integer), 2502(String), 1(Integer)
     *    Updates: 1
     * ting: org.activiti.engine.impl.persistence.entity.HistoricTaskInstanceEntityImpl@4c4d27c8
     *  Preparing: update ACT_HI_TASKINST set PROC_DEF_ID_ = ?, EXECUTION_ID_ = ?, NAME_ = ?, PARENT_TASK_ID_ = ?, DESCRIPTION_ = ?, OWNER_ = ?, ASSIGNEE_ = ?, CLAIM_TIME_ = ?, END_TIME_ = ?, DURATION_ = ?, DELETE_REASON_ = ?, TASK_DEF_KEY_ = ?, FORM_KEY_ = ?, PRIORITY_ = ?, DUE_DATE_ = ?, CATEGORY_ = ? where ID_ = ?
     * Parameters: MyEvection:1:4(String), 2502(String), 创建出差申请(String), null, null, null, 张三(String), null, 2022-08-20 12:38:40.584(Timestamp), 2976593(Long), null, sid-7d4155ad-908b-4a3f-b474-29db1e5d3f79(String), null, 50(Integer), null, null, 2505(String)
     *    Updates: 1
     * ting: HistoricActivityInstanceEntity[id=2504, activityId=sid-7d4155ad-908b-4a3f-b474-29db1e5d3f79, activityName=创建出差申请]
     *  Preparing: update ACT_HI_ACTINST set EXECUTION_ID_ = ?, ASSIGNEE_ = ?, END_TIME_ = ?, DURATION_ = ?, DELETE_REASON_ = ? where ID_ = ?
     * Parameters: 2502(String), 张三(String), 2022-08-20 12:38:40.619(Timestamp), 2976649(Long), null, 2504(String)
     *    Updates: 1
     *  Preparing: delete from ACT_RU_TASK where ID_ = ? and REV_ = ?
     * Parameters: 2505(String), 1(Integer)
     *    Updates: 1
     */
    @Test
    public void completeTaskByThisAssign() {
        // 获取任务记录
        final TaskQuery taskQuery = taskService.createTaskQuery();
        final Task task = taskQuery
                .processDefinitionKey("MyEvection")
                .taskAssignee("张三")
                .singleResult();

        if (null == task) return;

        final String id = task.getId();
        taskService.complete(id);
    }

    /**
     * 完成剩下的任务
     */
    @Test
    public void completeRemainingTask() {
        final TaskQuery taskQuery = taskService.createTaskQuery();
        String[] assigns = {"Jack张", "Mike李", "Rose梅"};
        for (String assign : assigns) {
            final Task task = taskQuery
                    .processDefinitionKey("MyEvection")
                    .taskAssignee(assign)
                    .singleResult();
            taskService.complete(task.getId());
        }
    }


    /**
     *  Preparing: select RES.* from ACT_HI_ACTINST RES WHERE RES.PROC_INST_ID_ = ? and RES.PROC_DEF_ID_ = ? order by RES.ID_ asc LIMIT ? OFFSET ?
     * Parameters: 2501(String), MyEvection:1:4(String), 2147483647(Integer), 0(Integer)
     *      Total: 6
     * 查询任务执行历史
     *
     */
    @Test
    public void getTaskHistory() {
        final HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery();

        final List<HistoricActivityInstance> activityInstanceList = query
                .processInstanceId("2501")
                .processDefinitionId("MyEvection:1:4")
                .list();

        for (HistoricActivityInstance activityInstance : activityInstanceList) {
            final String activityId = activityInstance.getActivityId();
            final String activityName = activityInstance.getActivityName();
            final String processDefinitionId = activityInstance.getProcessDefinitionId();
            final String processInstanceId = activityInstance.getProcessInstanceId();

            System.out.println("- - - - - - - - - - - - - - -");
            System.out.println("activityId = " + activityId);
            System.out.println("activityName = " + activityName);
            System.out.println("processInstanceId = " + processInstanceId);
            System.out.println("processDefinitionId = " + processDefinitionId);
        }
    }

    /**
     *
     * 删除流程定义
     */
    @Test
    public void deleteProcessDeployment() {
        final ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();

        final List<ProcessDefinition> processDefinitions = query
                .processDefinitionKey("MyEvection")
                .orderByProcessDefinitionVersion()
                .desc()
                .list();

        for (ProcessDefinition definition : processDefinitions) {
            final String deploymentId = definition.getDeploymentId();
            final String id = definition.getId();
            final String key = definition.getKey();
            final String name = definition.getName();
            final String description = definition.getDescription();
            final String resourceName = definition.getResourceName();

            System.out.println("resourceName = " + resourceName);
            System.out.println("description = " + description);
            System.out.println("name = " + name);
            System.out.println("key = " + key);
            System.out.println("id = " + id);
            System.out.println("deploymentId = " + deploymentId);

            // 按部署ID删除
            // repositoryService.deleteDeployment(deploymentId);

            // 级联删除，包括任务执行历史
            repositoryService.deleteDeployment(deploymentId, true);
        }
    }

    /**
     * "37501",
     * "45001",
     * "55001",
     * "65001",
     * "72501",
     * "75001",
     */
    @Test
    public void deleteDeploy() {
        String[] deployIds = {
            "120001"
        };
        for (String deployId : deployIds) {
            repositoryService.deleteDeployment(deployId, true);
        }
    }


    /**
     * 在流程启动时设置业务ID
     */
    @Test
    public void withBusinessKey() {
        final ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("MyEvection", "BUSINESS-1001");
        System.out.println(processInstance.getBusinessKey());
    }

    /**
     * 流程任务挂起和激活(全部挂起和激活)
     */
    @Test
    public void allTaskPauseAndActivate() {
        final ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
        final ProcessDefinition processDefinition = query
                .processDefinitionKey("MyEvection")
                .singleResult();

        final String definitionId = processDefinition.getId();

        // 判断流程是否为挂起状态, 如果激活则挂起，如果挂起则激活
        final boolean suspended = processDefinition.isSuspended();
        if (suspended) {
            // 流程定义ID，是否激活，激活截止日期
            repositoryService.activateProcessDefinitionById(definitionId, true, null);
        } else {
            // 流程定义ID，是否激活，激活截止日期
            repositoryService.suspendProcessDefinitionById(definitionId, true, null);
        }
    }

    /**
     * 指定具体任务挂起和激活
     * SELECT * FROM act_ru_task
     */
    @Test
    public void singleTaskPauseAndActivate() {
        final ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery();

        final ProcessInstance processInstance = query.processInstanceId("7501").singleResult();

        final String processInstanceId = processInstance.getId();

        final boolean suspended = processInstance.isSuspended();
        if (suspended) {
            // 流程定义ID，是否激活，激活截止日期
            runtimeService.activateProcessInstanceById(processInstanceId);
        } else {
            // 流程定义ID，是否激活，激活截止日期
            runtimeService.suspendProcessInstanceById(processInstanceId);
        }
    }

    /**
     * org.activiti.engine.ActivitiException: Cannot complete a suspended task
     * 不能完成一个被挂起的任务
     */
    @Test
    public void completeTaskWithSuspendedTest() {
        final TaskQuery taskQuery = taskService.createTaskQuery();

        final Task task = taskQuery
                .processDefinitionKey("MyEvection")
                .taskAssignee("张三")
                .processInstanceId("7501")
                .singleResult();

        taskService.complete(task.getId());
    }


}
